// 调度器模块
// 管理定时任务的执行

use crate::config::SyncConfig;
use crate::sync::DataSyncer;
use crate::trading_day::TradingCalendar;
use anyhow::{Context, Result};
use chrono::Local;
use tokio_cron_scheduler::{Job, JobScheduler};
use tracing::{error, info};

/// 任务调度器
pub struct Scheduler {
    /// 配置
    config: SyncConfig,
    /// 数据同步器
    syncer: DataSyncer,
    /// 交易日历
    calendar: TradingCalendar,
    /// cron 调度器
    job_scheduler: JobScheduler,
}

impl Scheduler {
    /// 创建新的调度器
    pub async fn new(config: SyncConfig) -> Result<Self> {
        let syncer = DataSyncer::new(config.clone())
            .await
            .context("创建数据同步器失败")?;
        
        let calendar = TradingCalendar::new();
        
        let job_scheduler = JobScheduler::new()
            .await
            .context("创建任务调度器失败")?;
        
        Ok(Self {
            config,
            syncer,
            calendar,
            job_scheduler,
        })
    }
    
    /// 启动调度器
    pub async fn start(&mut self) -> Result<()> {
        info!("启动定时任务调度器");
        
        // 添加每日数据记录任务（下午3点半）
        self.add_daily_record_job().await?;
        
        // 添加每日数据检查任务（早上8点）
        self.add_daily_check_job().await?;
        
        // 启动调度器
        self.job_scheduler
            .start()
            .await
            .context("启动调度器失败")?;
        
        info!("调度器已启动");
        Ok(())
    }
    
    /// 添加每日数据记录任务
    async fn add_daily_record_job(&mut self) -> Result<()> {
        let time = &self.config.schedule.daily_record_time;
        let parts: Vec<&str> = time.split(':').collect();
        
        if parts.len() != 3 {
            return Err(anyhow::anyhow!("无效的时间格式: {}", time));
        }
        
        let hour = parts[0];
        let minute = parts[1];
        let second = parts[2];
        
        // 构建 cron 表达式: "秒 分 时 * * *"
        let cron_expr = format!("{} {} {} * * *", second, minute, hour);
        
        info!("添加每日数据记录任务: {}", cron_expr);
        
        // 克隆需要的数据
        let syncer = self.syncer.clone();
        let calendar = TradingCalendar::new();
        
        let job = Job::new_async(cron_expr.as_str(), move |_uuid, _lock| {
            let syncer = syncer.clone();
            let calendar = calendar.clone();
            
            Box::pin(async move {
                info!("执行每日数据记录任务");
                
                let today = Local::now().date_naive();
                
                // 检查是否为交易日
                if !calendar.is_trading_day(today) {
                    info!("今天不是交易日，跳过数据记录");
                    return;
                }
                
                // 同步数据
                match DataSyncer::new(syncer.config).await {
                    Ok(syncer) => {
                        if let Err(e) = syncer.sync_all().await {
                            error!("数据同步失败: {}", e);
                        }
                    }
                    Err(e) => {
                        error!("创建数据同步器失败: {}", e);
                    }
                }
            })
        })
        .context("创建每日记录任务失败")?;
        
        self.job_scheduler
            .add(job)
            .await
            .context("添加每日记录任务失败")?;
        
        Ok(())
    }
    
    /// 添加每日数据检查任务
    async fn add_daily_check_job(&mut self) -> Result<()> {
        let time = &self.config.schedule.daily_check_time;
        let parts: Vec<&str> = time.split(':').collect();
        
        if parts.len() != 3 {
            return Err(anyhow::anyhow!("无效的时间格式: {}", time));
        }
        
        let hour = parts[0];
        let minute = parts[1];
        let second = parts[2];
        
        // 构建 cron 表达式
        let cron_expr = format!("{} {} {} * * *", second, minute, hour);
        
        info!("添加每日数据检查任务: {}", cron_expr);
        
        // 克隆需要的数据
        let syncer = self.syncer.clone();
        let calendar = TradingCalendar::new();
        
        let job = Job::new_async(cron_expr.as_str(), move |_uuid, _lock| {
            let syncer = syncer.clone();
            let calendar = calendar.clone();
            
            Box::pin(async move {
                info!("执行每日数据检查任务");
                
                let today = Local::now().date_naive();
                
                // 获取上一个交易日
                let prev_trading_day = match calendar.get_previous_trading_day(today) {
                    Some(date) => date,
                    None => {
                        error!("无法获取上一个交易日");
                        return;
                    }
                };
                
                info!("上一个交易日: {}", prev_trading_day);
                
                // 检查是否有上个交易日的数据
                match calendar.has_data_for_date(prev_trading_day).await {
                    Ok(has_data) => {
                        if !has_data {
                            info!("缺少上个交易日 {} 的数据，开始补录", prev_trading_day);
                            
                            // 创建同步器并补录数据
                            match DataSyncer::new(syncer.config).await {
                                Ok(syncer) => {
                                    if let Err(e) = syncer.check_and_backfill(prev_trading_day).await {
                                        error!("补录数据失败: {}", e);
                                    }
                                }
                                Err(e) => {
                                    error!("创建数据同步器失败: {}", e);
                                }
                            }
                        } else {
                            info!("上个交易日 {} 的数据已存在", prev_trading_day);
                        }
                    }
                    Err(e) => {
                        error!("检查数据失败: {}", e);
                    }
                }
            })
        })
        .context("创建每日检查任务失败")?;
        
        self.job_scheduler
            .add(job)
            .await
            .context("添加每日检查任务失败")?;
        
        Ok(())
    }
    
    /// 停止调度器
    pub async fn stop(&mut self) -> Result<()> {
        info!("停止调度器");
        self.job_scheduler
            .shutdown()
            .await
            .context("停止调度器失败")?;
        Ok(())
    }
    
    /// 运行调度器（阻塞）
    pub async fn run(mut self) -> Result<()> {
        self.start().await?;
        
        // 保持运行
        info!("调度器正在运行，按 Ctrl+C 停止");
        
        // 等待 Ctrl+C 信号
        tokio::signal::ctrl_c()
            .await
            .context("等待信号失败")?;
        
        info!("收到停止信号");
        self.stop().await?;
        
        Ok(())
    }
}

// 已将字段改为公共访问，不再需要这些方法

#[cfg(test)]
mod tests {
    use super::*;
    
    #[tokio::test]
    async fn test_scheduler_creation() {
        let config = SyncConfig::from_file("../../../config/sync_config.toml");
        if let Ok(config) = config {
            let scheduler = Scheduler::new(config).await;
            assert!(scheduler.is_ok());
        }
    }
}
